package net.goutalk.glcs.module.erpModel.caseErpBom.controller;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.yulichang.toolkit.MPJWrappers;
import net.goutalk.glcs.common.annotation.GlcsLog;
import net.goutalk.glcs.common.constant.GlobalConstant;
import net.goutalk.glcs.common.model.result.R;
import net.goutalk.glcs.common.utils.TreeUtil;
import net.goutalk.glcs.common.utils.VoToColumnUtil;
import net.goutalk.glcs.module.erpModel.caseErpBom.dto.AddCaseErpBomDto;
import net.goutalk.glcs.module.erpModel.caseErpBom.dto.ImportCaseErpBomDto;
import net.goutalk.glcs.module.erpModel.caseErpBom.dto.ImportCaseErpBomVo;
import net.goutalk.glcs.module.erpModel.caseErpBom.dto.UpdateCaseErpBomDto;
import net.goutalk.glcs.module.erpModel.caseErpBom.entity.CaseErpBom;
import net.goutalk.glcs.module.erpModel.caseErpBom.service.ICaseErpBomService;
import net.goutalk.glcs.module.erpModel.caseErpBom.vo.CaseErpBomExportVo;
import net.goutalk.glcs.module.erpModel.caseErpBom.vo.CaseErpBomTreeVo;
import net.goutalk.glcs.module.erpModel.caseErpBom.vo.CaseErpBomVo;
import net.goutalk.glcs.module.erpModel.caseErpMaterial.entity.CaseErpMaterial;
import net.goutalk.glcs.module.erpModel.caseErpMaterial.service.ICaseErpMaterialService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.validation.Valid;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * BOM信息【case_erp_bom】 前端控制器
 * </p>
 *
 * @author hnyyzy
 * @since 2023-06-19
 */
@RestController
@RequestMapping(GlobalConstant.CASE_ERP_BOM +"/caseErpBom")
@Api(value = GlobalConstant.CASE_ERP_BOM +"/caseErpBom", tags = "BOM信息")
@AllArgsConstructor
public class CaseErpBomController {
    private ICaseErpBomService caseErpBomService;

    private ICaseErpMaterialService caseErpMaterialService;

    @GetMapping(value = "/tree")
    @ApiOperation(value = "Bom信息树")
    @GlcsLog(value = "Bom信息 所有数据")
    public R tree() {
        List<CaseErpBom> list = caseErpBomService.list(Wrappers.<CaseErpBom>lambdaQuery()
                        .orderByDesc(CaseErpBom::getCreateDate)
                .select(CaseErpBom.class, x -> VoToColumnUtil.fieldsToColumns(CaseErpBomTreeVo.class).contains(x.getProperty())));
        List<CaseErpBomTreeVo> voList = BeanUtil.copyToList(list, CaseErpBomTreeVo.class);
        List<CaseErpBomTreeVo> treeVoList = TreeUtil.build(voList);
        return R.ok(treeVoList);
    }

    @GetMapping("/verification")
    @ApiOperation(value = "系统验证")
    public R verification(@RequestParam Long id){
        List<CaseErpBom> list = caseErpBomService.list();
        List<Long> ids = list.stream().map(o -> o.getMaterialId()).collect(Collectors.toList());
        if(ids.contains(id)){
            return R.error("该物料已进行过bom配置不能再次配置");
        }else {
            return R.ok();
        }
    }

    @PostMapping
    @ApiOperation(value = "新增BOM物料")
    public R add(@RequestBody AddCaseErpBomDto dto){
        List<CaseErpBom> list = caseErpBomService.list();
        List<CaseErpMaterial> caseErpMaterialList = caseErpMaterialService.list();
        CaseErpBom copy = BeanUtil.toBean(dto, CaseErpBom.class);
        if(ObjectUtil.isNotEmpty(dto.getParentId()) && dto.getParentId()!= 0L){
            CaseErpBom caseErpBom = list.stream().filter(x -> x.getId().equals(dto.getParentId())).findFirst().orElse(new CaseErpBom());
            if (StrUtil.isNotBlank(caseErpBom.getBomLevel())){
                List<Long> ids = StrUtil.split(caseErpBom.getBomLevel().toString(), StringPool.DASH)
                        .stream().map(str -> Long.valueOf(str)).collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(ids)){
                    List<Long> materialIds = list.stream().filter(x -> ids.contains(x.getId())).map(CaseErpBom::getMaterialId).collect(Collectors.toList());
                    if(materialIds.contains(dto.getMaterialId())){
                        return R.error("不允许添加包括该子物料在内和所有直系的上级物料");
                    }
                }
            }
        }
        else {
            copy.setCount(new BigDecimal("1"));
            copy.setParentId(0L);
        }
        if (StrUtil.isNotBlank(copy.getCode())){
            CaseErpMaterial caseErpMaterial = caseErpMaterialList.stream().filter(x -> x.getCode().equals(copy.getCode())).findFirst().orElse(new CaseErpMaterial());
            if (ObjectUtil.isNotEmpty(caseErpMaterial.getId())){
                copy.setMaterialId(caseErpMaterial.getId());
            }else {
                R.error("此物料不存在");
            }
        }
        caseErpBomService.save(copy);
        //保存层级
        if (ObjectUtil.isNotEmpty(dto.getParentId())&& dto.getParentId()!= 0L){
            CaseErpBom caseErpBom = list.stream().filter(x -> x.getId().equals(dto.getParentId())).findFirst().orElse(new CaseErpBom());
            copy.setBomLevel(caseErpBom.getBomLevel()+ StringPool.DASH + copy.getId());
        }else {
            copy.setBomLevel(copy.getId().toString());
        }
        caseErpBomService.updateById(copy);
        return R.ok();
    }

    @GetMapping(value = "/info")
    @ApiOperation(value = "根据id查询物料信息(当前以及子级信息)")
    public R info(@RequestParam(required = false) Long id) {
        if (ObjectUtil.isNotEmpty(id)){
            CaseErpBomVo caseErpBomVo = caseErpBomService.selectJoinOne(CaseErpBomVo.class,
                    MPJWrappers.<CaseErpBom>lambdaJoin()
                            .distinct()
                            .eq(CaseErpBom::getId,id)
                            .select(CaseErpBom::getId)
                            .select(CaseErpBom.class, x -> VoToColumnUtil.fieldsToColumns(CaseErpBomVo.class).contains(x.getProperty())));
            //子级物料信息
            List<Long> childIds = caseErpBomService.list().stream().filter(x -> StrUtil.isNotBlank(x.getBomLevel())
                    && x.getBomLevel().contains(id + StringPool.DASH)).map(CaseErpBom::getId).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(childIds)){
                List<CaseErpBomVo> caseErpBomVoList = caseErpBomService.selectJoinList(CaseErpBomVo.class,
                        MPJWrappers.<CaseErpBom>lambdaJoin()
                                .distinct()
                                .in(CaseErpBom::getId, childIds)
                                .select(CaseErpBom::getId)
                                .select(CaseErpBom.class, x -> VoToColumnUtil.fieldsToColumns(CaseErpBomVo.class).contains(x.getProperty())));
                if (CollectionUtil.isNotEmpty(caseErpBomVoList)){
                    caseErpBomVo.setChildList(caseErpBomVoList);
                }
            }
            CaseErpBomVo arr[];
            arr = new CaseErpBomVo[1];
            arr[0] = caseErpBomVo;
            return R.ok(arr);
        }else {
            return R.ok();
        }

    }

    @PutMapping
    @ApiOperation(value = "修改Bom信息")
    public R update(@Valid @RequestBody UpdateCaseErpBomDto dto) {
        List<CaseErpBom> list = caseErpBomService.list();
        if(ObjectUtil.isNotEmpty(dto.getParentId())){
            CaseErpBom caseErpBom = list.stream().filter(x -> x.getId().equals(dto.getParentId())).findFirst().orElse(new CaseErpBom());
            if (StrUtil.isNotBlank(caseErpBom.getBomLevel())){
                //上级bom信息
                List<Long> ids = StrUtil.split(caseErpBom.getBomLevel().toString(), StringPool.DASH)
                        .stream().map(str -> Long.valueOf(str)).collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(ids)){
                    List<Long> materialIds = list.stream().filter(x -> ids.contains(x.getId())).map(CaseErpBom::getMaterialId).collect(Collectors.toList());
                    if(materialIds.contains(dto.getMaterialId())){
                        return R.error("不允许修改包括该子物料在内和所有直系的上级物料");
                    }
                }
                //下级bom信息
                List<Long> childIds = list.stream().filter(x -> StrUtil.isNotBlank(x.getBomLevel())
                        && x.getBomLevel().contains(caseErpBom.getId() + StringPool.DASH)).map(CaseErpBom::getId).collect(Collectors.toList());
                if (CollectionUtil.isNotEmpty(childIds)){
                    List<Long> materialIds = list.stream().filter(x -> childIds.contains(x.getId())).map(CaseErpBom::getMaterialId).collect(Collectors.toList());
                    if(materialIds.contains(dto.getMaterialId())){
                        return R.error("不允许修改成为：该级别物料子物料在内和所有直系的下级物料");
                    }
                }
            }
        }
        CaseErpBom copy = BeanUtil.toBean(dto, CaseErpBom.class);
        List<CaseErpMaterial> caseErpMaterialList = caseErpMaterialService.list();
        if (StrUtil.isNotBlank(copy.getCode())){
            CaseErpMaterial caseErpMaterial = caseErpMaterialList.stream().filter(x -> x.getCode().equals(copy.getCode())).findFirst().orElse(new CaseErpMaterial());
            if (ObjectUtil.isNotEmpty(caseErpMaterial.getId())){
                copy.setMaterialId(caseErpMaterial.getId());
            }else {
                R.error("此物料不存在");
            }
        }
        caseErpBomService.updateById(copy);
        return R.ok(true);
    }


    @DeleteMapping
    @ApiOperation(value = "删除")
    @GlcsLog(value = "删除bom信息")
    public R delete(@Valid @RequestBody Long id) {
        List<CaseErpBom> list = caseErpBomService.list();
        CaseErpBom caseErpBom = list.stream().filter(x -> x.getId().equals(id)).findFirst().orElse(new CaseErpBom());
        if (ObjectUtil.isNotEmpty(caseErpBom)){
            //下级物料信息
            List<Long> childIds = list.stream().filter(x -> StrUtil.isNotBlank(x.getBomLevel())
                    && x.getBomLevel().contains(caseErpBom.getId() + StringPool.DASH)).map(CaseErpBom::getId).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(childIds)){
                return R.error("存在下级物料信息，不允许删除");
            }
            else {
                caseErpBomService.removeById(id);
            }
        }
        return R.ok();
    }

    @PostMapping(value = "/export")
    @ApiOperation(value = "导出")
    @GlcsLog(value = "导出Bom信息")
    public ResponseEntity<byte[]> exportAll() {
        List<CaseErpBomExportVo> caseErpBomVoList = caseErpBomService.selectJoinList(CaseErpBomExportVo.class,
                MPJWrappers.<CaseErpBom>lambdaJoin()
                        .distinct()
                        .select(CaseErpBom::getId)
                        .select(CaseErpBom.class, x -> VoToColumnUtil.fieldsToColumns(CaseErpBomExportVo.class).contains(x.getProperty())));
        ByteArrayOutputStream bot = new ByteArrayOutputStream();

        EasyExcel.write(bot, CaseErpBomExportVo.class).excelType(ExcelTypeEnum.XLSX).sheet().doWrite(caseErpBomVoList);
        return R.fileStream(bot.toByteArray(), "产品Bom信息" + ExcelTypeEnum.XLSX.getValue());
    }

    @PostMapping("/import")
    @ApiOperation(value = "导入")
    public R importData(@RequestParam MultipartFile file) throws IOException {
        List<ImportCaseErpBomVo> voList = EasyExcel.read(file.getInputStream()).head(ImportCaseErpBomVo.class).sheet().doReadSync();
        List<ImportCaseErpBomDto> importCaseErpBomDtoList = BeanUtil.copyToList(voList, ImportCaseErpBomDto.class);
        List<CaseErpMaterial> caseErpMaterialList = caseErpMaterialService.list();
        List<CaseErpBom> list = caseErpBomService.list();
        List<AddCaseErpBomDto> addCaseErpBomDtoList = new ArrayList<>();
        for (ImportCaseErpBomDto importCaseErpBomDto : importCaseErpBomDtoList) {
            if (StrUtil.isBlank(importCaseErpBomDto.getParentName())){
                importCaseErpBomDto.setParentId(0L);
            }else {
                CaseErpBom caseErpBom = list.stream().filter(x -> x.getName().equals(importCaseErpBomDto.getParentName())).findFirst().orElse(new CaseErpBom());
                if (ObjectUtil.isNotEmpty(caseErpBom.getId())){
                    importCaseErpBomDto.setParentId(caseErpBom.getId());
                }else {
                    importCaseErpBomDto.setParentId(0L);
                    return R.error("父级名称填写错误");
                }
            }
            AddCaseErpBomDto addCaseErpBomDto = BeanUtil.toBean(importCaseErpBomDto, AddCaseErpBomDto.class);
            if (StrUtil.isNotBlank(importCaseErpBomDto.getCode())){
                CaseErpMaterial caseErpMaterial = caseErpMaterialList.stream().filter(x -> x.getCode().equals(importCaseErpBomDto.getCode())).findFirst().orElse(new CaseErpMaterial());
                if (ObjectUtil.isNotEmpty(caseErpMaterial.getId())){
                    addCaseErpBomDto.setMaterialId(caseErpMaterial.getId());
                }else {
                    return R.error("此物料不存在");
                }
            }
            addCaseErpBomDtoList.add(addCaseErpBomDto);
        }
        List<CaseErpBom> caseErpBomList =  BeanUtil.copyToList(addCaseErpBomDtoList, CaseErpBom.class);
        caseErpBomService.saveBatch(caseErpBomList);
        for (CaseErpBom caseErpBom : caseErpBomList) {
            //保存层级
            if (ObjectUtil.isNotEmpty(caseErpBom.getParentId())&& caseErpBom.getParentId()!= 0L){
                CaseErpBom caseErpBom1 = list.stream().filter(x -> x.getId().equals(caseErpBom.getParentId())).findFirst().orElse(new CaseErpBom());
                caseErpBom.setBomLevel(caseErpBom1.getBomLevel()+ StringPool.DASH + caseErpBom.getId());
            }else {
                caseErpBom.setBomLevel(caseErpBom.getId().toString());
            }
        }
        caseErpBomService.updateBatchById(caseErpBomList);
        return R.ok(true);
    }

    @GetMapping("/export")
    @ApiOperation(value = "下载模板")
    @SneakyThrows
    public ResponseEntity<byte[]> export() {
        List<ImportCaseErpBomVo> caseErpBomVoList = new ArrayList<>();
        ByteArrayOutputStream bot = new ByteArrayOutputStream();
        EasyExcel.write(bot, ImportCaseErpBomVo.class).excelType(ExcelTypeEnum.XLSX).sheet().doWrite(BeanUtil.copyToList(caseErpBomVoList, ImportCaseErpBomVo.class));
        return R.fileStream(bot.toByteArray(), "产品Bom信息模板" + ExcelTypeEnum.XLSX.getValue());
    }

}
